package com.yjj.demo.spring.redis.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 *
 * @author yangjiajia
 * @createdAt 2022/10/15 19:53
 */
@Service
public class LuckDrawService {

    private Logger logger = LoggerFactory.getLogger(LuckDrawService.class);

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private final String code = "code";
    private final String usedCode = "usedCode";

    private final int CODE_COUNT = 100;

    private final int MIN_COUNT = 20;

    private Lock lock = new ReentrantLock();
    private AtomicInteger surplus = new AtomicInteger(0);

    @PostConstruct
    public void init() {
        Long size = stringRedisTemplate.opsForSet().size(code);
        int currentCount = 0;
        if (size != null) {
            currentCount = size.intValue();
        }
        surplus.set(currentCount);
        if (currentCount >= MIN_COUNT) {
            logger.info("中奖吗数量足够,不需要生成");
            return;
        }
        generatorCode();
    }

    public int getAndGeneratorCode() {
        String randomValue = stringRedisTemplate.opsForSet().pop(code);

        stringRedisTemplate.opsForList().rightPush(usedCode, randomValue);

        generatorCode();

        logger.info("获取一个code,剩余:{}个", surplus.get());

        return Integer.parseInt(randomValue);
    }

    private void generatorCode() {
        try {
            lock.lock();

            int currentCount = surplus.decrementAndGet();
            if (currentCount > MIN_COUNT) {
                return;
            }
            logger.info("补充code");

            Set<String> set = new HashSet<>();
            Random random = new Random();

            //当天已使用code
            List<String> usedCodeList = stringRedisTemplate.opsForList().range(usedCode, 0, -1);

            while (true) {
                int randomNum = random.nextInt(10000000, 99999999);
                String code = String.valueOf(randomNum);
                if (!CollectionUtils.isEmpty(usedCodeList) && usedCodeList.contains(code)) {
                    continue;
                }
                set.add(code);
                if (set.size() >= CODE_COUNT) {
                    break;
                }
            }

            LocalDateTime localDate = LocalDate.now().plusDays(1).atStartOfDay();
            Instant instant = localDate.toInstant(ZoneOffset.of("+8"));
            stringRedisTemplate.opsForSet().add(code, set.toArray(new String[]{}));
            stringRedisTemplate.opsForList().rightPush(usedCode, "0");
            stringRedisTemplate.expireAt(usedCode, instant);

            long size = stringRedisTemplate.opsForSet().size(code);
            surplus.set((int)size);
        } finally {
            lock.unlock();
        }
    }
}
